{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Jupyter widgets UI CSS helper\n",
    "\n",
    "CSS styling of Jupyter Widgets is not particulary intuitive for those with little experience of CSS; this notebook is an attempt help alleviate this pain.\n",
    "\n",
    "This notebook generates an UI and some example widgets to enable the user interactively play with CSS layout settings.\n",
    "\n",
    "The Python code to reproduce this layout is also outputted to a text Widget. \n",
    "\n",
    "n.b.  The flex-direction, flex-wrap, display and align_content drop-downs do not appear to affect the layout.  Why is this??\n",
    "\n",
    "## Doug Redden, Feb 2018.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import ipywidgets as widgets"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Set up widgets on which layout will be demonstrated\n",
    "\n",
    "### Create some widgets to be placed in the layout demo box\n",
    "\n",
    "Any widgets can be generated to be placed in layout demo box.  In this case we create 5 buttons."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "item_layout = widgets.Layout(height='80px', min_width='30px', min_height='50px', width ='60px',flex_wrap='wrap')\n",
    "button_styles = ['primary',\n",
    "'success',\n",
    "'info',\n",
    "'warning',\n",
    "'danger']\n",
    "\n",
    "items = [widgets.Button(layout=item_layout, description=str(i), button_style=button_styles[i]) for i in range(5)]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create box to hold the layout demo widgets\n",
    "\n",
    "The widget deisplayed below will be embedded in a larger widget later in the notebook. That larger widget lets you interactively change the layout of this widget."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "box_layout = widgets.Layout(overflow_x='scroll',\n",
    "                    border='3px solid black',\n",
    "                    width='700px',\n",
    "                    min_width='50px',\n",
    "                    max_width='1000px',\n",
    "                    min_height='50px',\n",
    "                    max_height='1000px',\n",
    "                    height='300px',\n",
    "                    flex_direction='row',\n",
    "                    display='flex')\n",
    "\n",
    "widgetGroup = widgets.Box(children=items, layout=box_layout)\n",
    "\n",
    "widgetGroupAndTitle = widgets.VBox([widgets.Label('Widget area:'), widgetGroup],\n",
    "                                   layout=widgets.Layout(height='500px', width ='700px'))\n",
    "\n",
    "widgetGroupAndTitle"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Construct widget with controls for changing layout"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create a text area widget where the Python code to reproduce the CSS programmatically."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pythonCode = widgets.Textarea(\n",
    "    value='',\n",
    "    placeholder='Python code is exported to this panel....',\n",
    "    description='',\n",
    "    disabled=False\n",
    ")\n",
    "\n",
    "pythonCode.layout.width = '80%'\n",
    "pythonCode.layout.height = '80px'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create drop downs for choices of `overflow` in `x` and `y`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Set a uniform description width to make alignment easier\n",
    "style = {'description_width': '100px'}\n",
    "\n",
    "# Define one of two lists that will hold controls for changing the layout\n",
    "vboxList = []\n",
    "\n",
    "# Widget to present overflow style options for x\n",
    "overflow_x = widgets.Dropdown(\n",
    "    options=['scroll','hidden','auto','visible','initial','inherit'] ,\n",
    "    value = widgetGroup.layout.overflow_x,\n",
    "    description='overflow_x:',\n",
    "    disabled=False,\n",
    "    style=style,\n",
    ")\n",
    "\n",
    "# Add the \n",
    "vboxList.append(overflow_x)\n",
    "\n",
    "# Set up observer to watch for changes in selected overflow style and apply  \n",
    "# selected style to widgetGroup.\n",
    "def on_overflow_xchange(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.overflow_x = change.new\n",
    "        \n",
    "        # Note how easy it is to get the Python code to generate the layout!\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "overflow_x.observe(on_overflow_xchange)      \n",
    "    \n",
    "    \n",
    "# Widget to present overflow style options for y\n",
    "   \n",
    "overflow_y = widgets.Dropdown(\n",
    "    options=['scroll','hidden','auto','visible','initial','inherit'] ,\n",
    "    value='scroll',\n",
    "    description='overflow_y:',\n",
    "    disabled=False,\n",
    "    style=style,\n",
    ")\n",
    "vboxList.append(overflow_y)\n",
    "\n",
    "\n",
    "def on_overflow_y_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.overflow_y = change.new\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "overflow_y.observe(on_overflow_y_change)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Add some choices for the border around our layout demo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "border = widgets.Dropdown(\n",
    "    options=['3px solid black', '1px dashed black','2px solid black','3px solid blue', ],\n",
    "    value = widgetGroup.layout.border,\n",
    "    description='border:',\n",
    "    disabled=False,\n",
    "    style=style,\n",
    ")\n",
    "\n",
    "vboxList.append(border)\n",
    "\n",
    "def on_border_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.border = change.new\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "border.observe(on_border_change)      "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Add dropdowns for several CSS layout options"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# flex-flow opetions\n",
    "\n",
    "flex_flow = widgets.Dropdown(\n",
    "    options=[\n",
    "        'column-reverse',\n",
    "        'column',\n",
    "        'row',\n",
    "        'row-reverse',\n",
    "    ],\n",
    "    value='row',\n",
    "    description='flex-flow:',\n",
    "    disabled=False,\n",
    "    style=style,\n",
    ")\n",
    "vboxList.append(flex_flow)\n",
    "def on_flex_flow_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.flex_flow = change.new\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "flex_flow.observe(on_flex_flow_change)      \n",
    "\n",
    "# flex-direction options\n",
    "flex_direction = widgets.Dropdown(\n",
    "    options=[\n",
    "        'column-reverse',\n",
    "        'column',\n",
    "        'row',\n",
    "        'row-reverse',\n",
    "    ],\n",
    "    value='row',\n",
    "    description='flex-direction:',\n",
    "    disabled=False,\n",
    "    style=style,\n",
    ")\n",
    "vboxList.append(flex_direction)\n",
    "def on_flex_direction_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.flex_direction = change.new\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "flex_direction.observe(on_flex_direction_change)      \n",
    "\n",
    "# display options\n",
    "\n",
    "display = widgets.Dropdown(\n",
    "    options=['flex', 'inline-flex'],\n",
    "    value='flex',\n",
    "    description='display:',\n",
    "    disabled=False,\n",
    "    style=style,\n",
    ")\n",
    "vboxList.append(display)\n",
    "def on_display_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.display = change.new\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "display.observe(on_display_change)      \n",
    "\n",
    "# flex-wrap options\n",
    "\n",
    "flex_wrap = widgets.Dropdown(\n",
    "    options=[\n",
    "        'nowrap',\n",
    "        'wrap',\n",
    "        'wrap-reverse',\n",
    "    ],\n",
    "    value='nowrap',\n",
    "    description='flex-wrap:',\n",
    "    disabled=False,\n",
    "    style=style,\n",
    ")\n",
    "vboxList.append(flex_wrap)\n",
    "def on_flex_wrap_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.flex_wrap = change.new\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "flex_wrap.observe(on_flex_wrap_change)      \n",
    "\n",
    "# justify-content options\n",
    "\n",
    "justify_content = widgets.Dropdown(\n",
    "    options=[\n",
    "        'flex-start',\n",
    "        'flex-end',\n",
    "        'center',\n",
    "        'space-between',\n",
    "        'space-around',\n",
    "    ],\n",
    "    value='flex-start',\n",
    "    description='justify_content:',\n",
    "    disabled=False,\n",
    "    style=style,\n",
    ")\n",
    "\n",
    "vboxList.append(justify_content)\n",
    "def on_justify_content_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.justify_content = change.new\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "justify_content.observe(on_justify_content_change)      \n",
    "\n",
    "# align-items options\n",
    "\n",
    "align_items = widgets.Dropdown(\n",
    "    options=[\n",
    "        'flex-start',\n",
    "        'flex-end',\n",
    "        'center',\n",
    "        'baseline',\n",
    "        'stretch',\n",
    "    ],\n",
    "    value='stretch',\n",
    "    description='align_items:',\n",
    "    disabled=False,\n",
    "    style=style,\n",
    ")\n",
    "vboxList.append(align_items)\n",
    "def on_align_items_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.align_items = change.new\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "align_items.observe(on_align_items_change)      \n",
    "\n",
    "\n",
    "# align-content options\n",
    "\n",
    "align_content = widgets.Dropdown(\n",
    "    options=[\n",
    "        'flex-start', \n",
    "        'flex-end', \n",
    "        'center', \n",
    "        'space-between', \n",
    "        'space-around', \n",
    "        'space-evenly', \n",
    "        'stretch', \n",
    "        'inherit', \n",
    "        'initial', \n",
    "        'unset'],\n",
    "    value='stretch',\n",
    "    description='align_content:',\n",
    "    disabled=False,\n",
    "    style=style,\n",
    ")\n",
    "vboxList.append(align_content)\n",
    "def on_align_content_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.align_content = change.new\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "align_content.observe(on_align_content_change)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Set up `VBox` for holding these controls"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vbox_style_options  = widgets.VBox(vboxList)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Set up controls for changing sizes of layout demo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# These controls will be grouped together in one VBox. Items added to the list \n",
    "# below will be placed in that VBox\n",
    "\n",
    "vboxwidgetSizeList =[]\n",
    "\n",
    "\n",
    "sizeButtonWidth = '40px'\n",
    "buttonLayout = widgets.Layout(width=sizeButtonWidth)\n",
    "\n",
    "# Button/slider combination for adjusting width\n",
    "width_px_percent = widgets.ToggleButtons(\n",
    "    options=['px', '%',],\n",
    "    description='',\n",
    "    disabled=False,\n",
    "    button_style='', # 'success', 'info', 'warning', 'danger' or ''\n",
    "    tooltips=['Pixels', 'Percent of page',],\n",
    ")\n",
    "width_px_percent.style.button_width = sizeButtonWidth   \n",
    "\n",
    "width = widgets.IntSlider(\n",
    "    value = int(widgetGroup.layout.width.replace('%','').replace('px','')),\n",
    "    min=0,\n",
    "    max=1000,\n",
    "    step=1,\n",
    "    description='width:',\n",
    "    disabled=False,\n",
    "    continuous_update=False,\n",
    "    orientation='horizontal',\n",
    "    readout=True,\n",
    "    readout_format='d'\n",
    ")\n",
    "def on_width_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.width = str(change.new) + width_px_percent.value\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "width.observe(on_width_change)      \n",
    "\n",
    "\n",
    "\n",
    "vboxwidgetSizeList.append(widgets.HBox([width, width_px_percent]))\n",
    "                \n",
    "def on_width_px_percent_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.width = str(width.value) + change.new\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "width_px_percent.observe(on_width_px_percent_change)      "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Same as above, but for height\n",
    "\n",
    "height = widgets.IntSlider(\n",
    "    value = int(widgetGroup.layout.height.replace('%','').replace('px','')),\n",
    "    min=0,\n",
    "    max=1000,\n",
    "    step=1,\n",
    "    description='height:',\n",
    "    disabled=False,\n",
    "    continuous_update=False,\n",
    "    orientation='horizontal',\n",
    "    readout=True,\n",
    "    readout_format='d'\n",
    ")\n",
    "def on_height_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.height = str(change.new) + height_px_percent.value\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "height.observe(on_height_change)      \n",
    "\n",
    "height_px_percent = widgets.ToggleButtons(\n",
    "    options=['px', '%',],\n",
    "    description='',\n",
    "    disabled=False,\n",
    "    button_style='', # 'success', 'info', 'warning', 'danger' or ''\n",
    "    tooltips=['Pixels', 'Percent of page',],\n",
    ")\n",
    "\n",
    "height_px_percent.style.button_width = sizeButtonWidth   # ipywidgets 7.0 and above\n",
    "\n",
    "vboxwidgetSizeList.append(widgets.HBox([height, height_px_percent]))\n",
    "                \n",
    "def on_height_px_percent_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.height = str(height.value) + change.new\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "height_px_percent.observe(on_height_px_percent_change)      "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Slider/buttons for min-width\n",
    "\n",
    "min_width = widgets.IntSlider(\n",
    "    value=int(widgetGroup.layout.min_width.replace('%','').replace('px','')),\n",
    "    min=0,\n",
    "    max=1000,\n",
    "    step=1,\n",
    "    description='min_width:',\n",
    "    disabled=False,\n",
    "    continuous_update=False,\n",
    "    orientation='horizontal',\n",
    "    readout=True,\n",
    "    readout_format='d'\n",
    ")\n",
    "\n",
    "def on_min_width_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.min_width = str(change.new) + min_width_px_percent.value\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "min_width.observe(on_min_width_change)      \n",
    "\n",
    "\n",
    "min_width_px_percent = widgets.ToggleButtons(\n",
    "    options=['px', '%',],\n",
    "    description='',\n",
    "    disabled=False,\n",
    "    button_style='', # 'success', 'info', 'warning', 'danger' or ''\n",
    "    tooltips=['Pixels', 'Percent of page',],\n",
    ")\n",
    "\n",
    "min_width_px_percent.style.button_width = sizeButtonWidth   # ipywidgets 7.0 and above\n",
    "\n",
    "vboxwidgetSizeList.append(widgets.HBox([min_width, min_width_px_percent]))\n",
    "                \n",
    "def on_min_width_px_percent_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.min_width = str(min_width.value) + change.new\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "min_width_px_percent.observe(on_min_width_px_percent_change)      "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Now set up max-width controls\n",
    "\n",
    "max_width = widgets.IntSlider(\n",
    "    value=int(widgetGroup.layout.max_width.replace('%','').replace('px','')),\n",
    "    min=0,\n",
    "    max=1000,\n",
    "    step=1,\n",
    "    description='max_width:',\n",
    "    disabled=False,\n",
    "    continuous_update=False,\n",
    "    orientation='horizontal',\n",
    "    readout=True,\n",
    "    readout_format='d'\n",
    ")\n",
    "\n",
    "def on_max_width_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.max_width = str(change.new) + max_width_px_percent.value\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "max_width.observe(on_max_width_change)      \n",
    "\n",
    "\n",
    "max_width_px_percent = widgets.ToggleButtons(\n",
    "    options=['px', '%',],\n",
    "    description='',\n",
    "    disabled=False,\n",
    "    button_style='', # 'success', 'info', 'warning', 'danger' or ''\n",
    "    tooltips=['Pixels', 'Percent of page',],\n",
    ")\n",
    "\n",
    "max_width_px_percent.style.button_width = sizeButtonWidth   # ipywidgets 7.0 and above\n",
    "\n",
    "vboxwidgetSizeList.append(widgets.HBox([max_width, max_width_px_percent]))\n",
    "                \n",
    "def on_max_width_px_percent_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.max_width = str(max_width.value) + change.new\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "max_width_px_percent.observe(on_max_width_px_percent_change)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# max-height controls\n",
    "max_height = widgets.IntSlider(\n",
    "    value=int(widgetGroup.layout.max_height.replace('%','').replace('px','')),\n",
    "    min=0,\n",
    "    max=1000,\n",
    "    step=1,\n",
    "    description='max_height:',\n",
    "    disabled=False,\n",
    "    continuous_update=False,\n",
    "    orientation='horizontal',\n",
    "    readout=True,\n",
    "    readout_format='d'\n",
    ")\n",
    "def on_max_height_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.max_height = str(change.new) + max_height_px_percent.value\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "max_height.observe(on_max_height_change)      \n",
    "\n",
    "max_height_px_percent = widgets.ToggleButtons(\n",
    "    options=['px', '%',],\n",
    "    description='',\n",
    "    disabled=False,\n",
    "    button_style='', # 'success', 'info', 'warning', 'danger' or ''\n",
    "    tooltips=['Pixels', 'Percent of page',],\n",
    ")\n",
    "\n",
    "max_height_px_percent.style.button_width = sizeButtonWidth   # ipywidgets 7.0 and above\n",
    "\n",
    "vboxwidgetSizeList.append(widgets.HBox([max_height, max_height_px_percent]))\n",
    "                \n",
    "def on_max_height_px_percent_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.max_height = str(max_height.value) + change.new\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "max_height_px_percent.observe(on_max_height_px_percent_change)      "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# min-height controls\n",
    "min_height = widgets.IntSlider(\n",
    "    value=int(widgetGroup.layout.min_height.replace('%','').replace('px','')),\n",
    "    min=0,\n",
    "    max=1000,\n",
    "    step=1,\n",
    "    description='min_height:',\n",
    "    disabled=False,\n",
    "    continuous_update=False,\n",
    "    orientation='horizontal',\n",
    "    readout=True,\n",
    "    readout_format='d'\n",
    ")\n",
    "\n",
    "def on_min_height_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.min_height = str(change.new) + min_height_px_percent.value\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "min_height.observe(on_min_height_change)      \n",
    "\n",
    "min_height_px_percent = widgets.ToggleButtons(\n",
    "    options=['px', '%',],\n",
    "    description='',\n",
    "    disabled=False,\n",
    "    button_style='', # 'success', 'info', 'warning', 'danger' or ''\n",
    "    tooltips=['Pixels', 'Percent of page',],\n",
    ")\n",
    "\n",
    "min_height_px_percent.style.button_width = sizeButtonWidth  \n",
    "\n",
    "vboxwidgetSizeList.append(widgets.HBox([min_height, min_height_px_percent]))\n",
    "                \n",
    "def on_min_height_px_percent_change(change):    \n",
    "    if change['type'] == 'change' and change['name'] == 'value':\n",
    "        widgetGroup.layout.min_height = str(min_height.value) + change.new\n",
    "        pythonCode.value = str(widgetGroup.layout)\n",
    "    \n",
    "min_height_px_percent.observe(on_min_height_px_percent_change)      "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create `VBox` to hold size controls"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "widgetSizeVbox  = widgets.VBox(vboxwidgetSizeList)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Colate all the widgets and display"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hbox  = widgets.HBox([vbox_style_options, widgetSizeVbox, ])\n",
    "vboxAll  = widgets.VBox([pythonCode, hbox, widgetGroupAndTitle, ])\n",
    "\n",
    "vboxAll"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "l = widgets.Layout()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "l.keys"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "hide_input": false,
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
